/**
 * 
 */
package co.fitstart.admin.service.impl;

import java.io.InputStream;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.demo2do.core.BusinessException;
import com.demo2do.core.persistence.GenericDaoSupport;
import com.demo2do.core.persistence.annotation.Dynamic;
import com.demo2do.core.support.Page;
import com.demo2do.core.utils.StringUtils;

import co.fitstart.admin.dao.CouponDao;
import co.fitstart.admin.dao.SatisfactionSurveyDao;
import co.fitstart.admin.dao.UserDao;
import co.fitstart.admin.entity.content.CouponBatchSearch;
import co.fitstart.admin.entity.content.CouponSearch;
import co.fitstart.admin.entity.content.CouponTemplateSearch;
import co.fitstart.admin.service.CouponService;
import co.fitstart.entity.coupon.Coupon;
import co.fitstart.entity.coupon.CouponBatch;
import co.fitstart.entity.coupon.CouponTemplate;
import co.fitstart.entity.coupon.ExpireType;
import co.fitstart.entity.coupon.stat.CouponTemplateStat;
import co.fitstart.entity.market.satisfaction.SatisfactionSurvey;
import co.fitstart.entity.user.User;

/**
 * @author Leo
 * @param <T> 
 *
 */
@Service("couponService")
public class CouponServiceImpl<T> extends DataServiceImpl<T> implements CouponService<T>  {
	
	private static final Logger logger = LoggerFactory.getLogger(CouponServiceImpl.class);
    
    @Dynamic
    private CouponDao couponDao;
    
    @Dynamic
    private UserDao userDao;

    @Dynamic
    private SatisfactionSurveyDao satisfactionSurveyDao;

    @Autowired
    private GenericDaoSupport genericDaoSupport;
    

    public List<Coupon> list(String couponCode) {
        // return satisfactionSurveyDao.list(couponCode, DiscountType.GIFT);
        return couponDao.list(couponCode);
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.coupon.CouponService#listCouponTemplates(com.demo2do.core.web.resolver.Page)
     */
    public List<CouponTemplate> listCouponTemplates(Page page) {
        List<CouponTemplate> result = couponDao.listCouponTemplate(page.getBeginIndex(), page.getMaxResultRecords());
        page.calculate(result.size());
        return result.size() > page.getEveryPage() ? result.subList(0, page.getEveryPage()) : result;
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.coupon.CouponService#listCouponBatches(com.demo2do.core.web.resolver.Page)
     */
    public List<CouponBatch> listCouponBatches(Page page) {
        List<CouponBatch> result = couponDao.listCouponBatch(page.getBeginIndex(), page.getMaxResultRecords());
        page.calculate(result.size());
        return result.size() > page.getEveryPage() ? result.subList(0, page.getEveryPage()) : result;
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.coupon.CouponService#listCoupons(co.fitstart.common.entity.coupon.CouponBatch, com.demo2do.core.web.resolver.Page)
     */
    public List<Coupon> listCoupons(CouponBatch couponBatch, Page page) {
        List<Coupon> coupons = couponDao.listCoupon(couponBatch, page.getBeginIndex(), page.getMaxResultRecords());
        page.calculate(coupons.size());
        return coupons.size() > page.getEveryPage() ? coupons.subList(0, page.getEveryPage()) : coupons;
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.coupon.CouponService#searchCouponTemplate(co.fitstart.admin.web.controller.coupon.CouponTemplateSearch, com.demo2do.core.web.resolver.Page)
     */
    @SuppressWarnings("unchecked")
    public List<CouponTemplate> searchCouponTemplate(CouponTemplateSearch couponTemplateSearch, Page page) {
        List<CouponTemplate> result = genericDaoSupport.searchForList(couponTemplateSearch.buildSentenceTemplate(), couponTemplateSearch.buildParameters(), page.getBeginIndex(), page.getMaxResultRecords());
        page.calculate(result.size());
        return result.size() > page.getEveryPage() ? result.subList(0, page.getEveryPage()) : result;
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.coupon.CouponService#searchCouponBatch(co.fitstart.admin.web.controller.coupon.CouponBatchSearch, com.demo2do.core.web.resolver.Page)
     */
    @SuppressWarnings("unchecked")
    public List<CouponBatch> searchCouponBatch(CouponBatchSearch couponBatchSearch, Page page) {
        List<CouponBatch> result = genericDaoSupport.searchForList(couponBatchSearch.buildSentenceTemplate(), couponBatchSearch.buildParameters(), page.getBeginIndex(), page.getMaxResultRecords());
        page.calculate(result.size());
        return result.size() > page.getEveryPage() ? result.subList(0, page.getEveryPage()) : result;
    }
    
    @SuppressWarnings("unchecked")
    public List<Coupon> searchCoupon(CouponSearch couponSearch, Page page) {
    	List<Coupon> result = genericDaoSupport.searchForList(couponSearch.buildSentenceTemplate(), couponSearch.buildParameters(), page.getBeginIndex(), page.getMaxResultRecords());
        page.calculate(result.size());
        return result.size() > page.getEveryPage() ? result.subList(0, page.getEveryPage()) : result;
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.coupon.CouponService#createCouponTemplate(co.fitstart.common.entity.coupon.CouponTemplate, java.math.BigDecimal, java.math.BigDecimal)
     */
    public void createCouponTemplate(CouponTemplate couponTemplate, BigDecimal inputAmount, BigDecimal inputMinAmount) {
        
        // save new coupon template
        genericDaoSupport.save(couponTemplate.initialize(inputAmount, inputMinAmount));
        
        // save new coupon templdate stat
        CouponTemplateStat couponTemplateStat = new CouponTemplateStat(couponTemplate);
        genericDaoSupport.save(couponTemplateStat);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.coupon.CouponService#createCouponBatch(co.fitstart.common.entity.coupon.CouponBatch)
     */
    public void createCouponBatch(CouponBatch couponBatch) {
        
        // 1. save couponBatch
        genericDaoSupport.save(couponBatch.initialize(couponBatch.getCouponTemplate()));
        
        // 2. search CouponTemplateStat in CouponTemplate
        Long couponTemplateId = couponBatch.getCouponTemplate().getId();
        CouponTemplateStat couponTemplateStat = couponDao.getCouponTemplateStat(couponTemplateId);
        
        // 3. update couponTemplateStat
        genericDaoSupport.update(couponTemplateStat.edit(couponBatch));
        
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.CouponService#editCouponTemplate(co.fitstart.entity.coupon.CouponTemplate, java.lang.String, java.math.BigDecimal, java.math.BigDecimal)
     */
    public void editCouponTemplate(CouponTemplate couponTemplate, String inputName, BigDecimal inputAmount,
            BigDecimal inputMinAmount) {
        
        CouponBatch couponBatch = couponDao.getCouponBatch(couponTemplate);
        
        if(couponBatch != null) {
            if(!(inputName.equals(couponTemplate.getName()))) {
                genericDaoSupport.update(couponBatch.editTemplateName(inputName));
            }
        }
        
        genericDaoSupport.update(couponTemplate.edit(inputName, inputAmount, inputMinAmount));
        
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.CouponService#ediCouponBatch(co.fitstart.entity.coupon.CouponBatch, co.fitstart.entity.coupon.ExpireType)
     */
    public void ediCouponBatch(CouponBatch couponBatch, ExpireType inputExpireType) {
        if(!(inputExpireType.equals(couponBatch.getExpireType()))) {
            if(inputExpireType.equals(ExpireType.FIXED_DATE)) {
                couponBatch = couponBatch.editEffectiveDays(0);
            } else if (inputExpireType.equals(ExpireType.FIXED_DAYS)) {
                couponBatch = couponBatch.editEffectiveDate();
            }
        }
        
        genericDaoSupport.update(couponBatch.editExpireType(inputExpireType));
    }
    
    @SuppressWarnings("unused")
	private void parse(Long batchId, InputStream inputStream) {
    	
    	// 0. prepare data
        List<Object> result = new LinkedList<Object>();
        DataFormatter formatter = new DataFormatter();
        
        try {

        	logger.trace("#parse() - Starting parsing upload file.");
        	
        	// 1. get workbook
            Workbook workbook = WorkbookFactory.create(inputStream);

            // 2. get sheet and rows
            Sheet sheet = workbook.getSheetAt(0);
            Iterator<Row> rows = sheet.iterator();

            while (rows.hasNext()) {
            	
            	Row row = rows.next();
                int rowNum = row.getRowNum();

                if (rowNum < 1) {
                    continue;
                }

                if (row == null){
                    logger.error("没有数据");
                } else {
                	User user = this.initUser(formatter, row);
                	if(user != null) {
                    	this.generateCouponByimport(batchId, user);
                    }
                }
            }
            
        } catch (Exception e) {
            logger.error("#parse() - Finishing parsing file with errors.", e);
            throw new BusinessException("导入数据失败！");
        }
    }
    
    private User initUser(DataFormatter formatter, Row row) throws ParseException {
    	String name = formatter.formatCellValue(row.getCell(1));
    	String mobile = formatter.formatCellValue(row.getCell(2));
    	User user = new User();
    	user.setName(name);
    	user.setMobile(mobile);
    	
    	return user;
    }
    
    @Override
    public void generateCoupon(Long batchId, InputStream inputStream) {
    	this.parse(batchId, inputStream);
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.ecommerce.CouponService#generateCoupon(co.fitstart.common.entity.ecommerce.coupon.CouponBatch)
     */
    public void generateCoupon(Long batchId) {
        
    	CouponBatch couponBatch = couponDao.getCouponBatch(batchId);
    	
        int restCount = couponBatch.getAmount() - couponBatch.getReleaseAmount();
        
        for (int i = 0; i < restCount; i++) {
            genericDaoSupport.save(new Coupon(couponBatch));
        }
        
        genericDaoSupport.update(couponBatch.editReleaseAmount(restCount));
    }
    
    private void generateCouponByimport(Long batchId, User user) {
    	
    	CouponBatch couponBatch = couponDao.getCouponBatch(batchId);
    	
    	// 1. 匹配identification 与 user的手机号。返回user
        User dataBaseUser = userDao.load(user.getMobile());
        
        if(dataBaseUser == null || StringUtils.isEmpty(dataBaseUser.getMobile())) {
        	logger.info("could not generate by user [{}]", user.getMobile());
        	return;
        }
        
        Coupon coupon = new Coupon(couponBatch, couponBatch.getExpireType(), dataBaseUser.getMobile(), dataBaseUser.getName(), dataBaseUser.getUnionid());
        genericDaoSupport.save(coupon);
        
        // 将user赋给coupon的user,把页面传进来的identification参数 update给coupon
        genericDaoSupport.update(coupon.identify(dataBaseUser.getId(), dataBaseUser.getMobile()));
        
        genericDaoSupport.update(couponBatch.editReleaseAmount(1).editClaimedAmount());
    }
    
    @Override
    public void generateCoupon(Long batchId, User user) {
    	
    	CouponBatch couponBatch = couponDao.getCouponBatch(batchId);
    	
    	// 1. 匹配identification 与 user的手机号。返回user
        User dataBaseUser = userDao.load(user.getMobile());
        
        if(dataBaseUser == null || StringUtils.isEmpty(dataBaseUser.getMobile())) {
        	throw new BusinessException("用户数据异常");
        }
        
        Coupon coupon = new Coupon(couponBatch, couponBatch.getExpireType(), dataBaseUser.getMobile(), dataBaseUser.getName(), dataBaseUser.getUnionid());
        genericDaoSupport.save(coupon);
        
        // 将user赋给coupon的user,把页面传进来的identification参数 update给coupon
        genericDaoSupport.update(coupon.identify(dataBaseUser.getId(), dataBaseUser.getMobile()));
        
        genericDaoSupport.update(couponBatch.editReleaseAmount(1).editClaimedAmount());
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.ecommerce.CouponService#identify(co.fitstart.common.entity.ecommerce.coupon.Coupon, java.lang.String)
     */
    public void identify(Coupon coupon, String identification) {
    	
        // 1. 匹配identification 与 user的手机号。返回user
        User user = userDao.load(identification);
        
        // 将user赋给coupon的user,把页面传进来的identification参数 update给coupon
        genericDaoSupport.update(coupon.identify(user.getId(), identification));
        
        // update coupon batch's claimed count
        genericDaoSupport.update(coupon.getBatch().editClaimedAmount());
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.CouponService#editCouponTemplateDescription(co.fitstart.entity.coupon.CouponTemplate, java.lang.String)
     */
    public void editCouponTemplateDescription(CouponTemplate couponTemplate, String description) {
        genericDaoSupport.update(couponTemplate.editDescription(description));
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.CouponService#useGiftCoupon(co.fitstart.entity.coupon.Coupon, java.lang.String)
     */
    public void useGiftCoupon(Coupon coupon, String gift) {
        if(coupon == null || !coupon.getStatus().isClaimed() || coupon.getRestDay() <= 0 || !coupon.getTemplate().getDiscountType().isGife()) {
            throw new BusinessException("优惠券异常");
        } else {
            genericDaoSupport.update(coupon.use());
            
            SatisfactionSurvey survey = satisfactionSurveyDao.load(coupon);
            if(survey != null) {
                genericDaoSupport.update(survey.editGift(gift));
            }
        }
    }
    
    public void useCoupon(Coupon coupon) {
    	if(coupon == null || !coupon.getStatus().isClaimed() || coupon.getRestDay() <= 0) {
            throw new BusinessException("优惠券异常");
        } else {
        	genericDaoSupport.update(coupon.use());
        }
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.admin.service.CouponService#loadCoupon(java.lang.String)
     */
    public Coupon loadCoupon(String couponCode) {
        
        List<Coupon> coupons = satisfactionSurveyDao.list(couponCode);
        
        if(org.apache.commons.collections.CollectionUtils.isNotEmpty(coupons)) {
            return coupons.get(0);
        } else {
            return null;
        }
    }
    
    @Override
    public CouponBatch getCouponBatch(Long id) {
    	return couponDao.getCouponBatch(id);
    }
    
    /*
     * 
     */
    public List<Coupon> listByBatch(CouponBatch couponBatch, Page page) {
    	List<Coupon> result = couponDao.listCoupon(couponBatch, page.getBeginIndex(), page.getMaxResultRecords());
        page.calculate(result.size());
        return result.size() > page.getEveryPage() ? result.subList(0, page.getEveryPage()) : result;
    }

}
